<?php
/**
 * 登陆、判断函数集
 */

class Auth {

	var $table          = 'tbl_user';
	var $login_url      = '/login.php?';
	var $uid            = 0;
	var $username       = 'username';
	var $password       = 'password';
	var $tb_id          = 'user_id';
	var $tb_username    = 'user_name';
	var $tb_password    = 'user_password';
	var $field          = array();
	var $key_prefix     = '3b84f8c12344e7211160037ebacbf0e7';
	var $error          = 1;
	var $cookie_key     = 'USER_AUTH';
	var $cookie_life    = 2592000;
	var $cookie_domain  = "";
	var $login_main     = "";

	function __construct($db = '', $table = '')
	{
		if (empty($db)) {
			exit("no db");
		}
		if (!empty($table)) {
			$this->table = $table;
		}

		$this->db = $db;
		if (empty($this->filed)){
			$this->filed = array($this->tbl_user, $this->tb_id);
		}
	}

	/** 执行功能函数并返回预定义信息 **/
	function dofun($fun = "", $param = array()){
		if (empty($fun) or method_exists("this", $fun)) {
			die("no method");
		} else {
			$return = call_user_func_array(array($this, $fun), (array)$param);
			// 返回成功和失败信息
			if ( $return >= 0) {
				$this->message($fun, 1);
				return $return;
			} else {
				$this->message($fun, $return);
			};
		}
	}

	/** 返回报错信息 **/
	function message($fun, $error){
		include ("config/msg.php");
		$this->msg = $msg[$fun][$error];
		$this->error = $error;
		if ($error < 0) {
			return false;
		}
	}

	/** 用户注册 **/
	function register($info){

		// 验证用户名是否已被注册
		if (!$this->check_usernameexists($info[$this->tb_username])) {
			return -1;
		}

		// 验证用户名是否规范
		if (!$this->check_usernameformat($info[$this->tb_password])) {
			return -2;
		}

		// 将密码md5加密
		$info[$this->tb_password] = md5($info[$this->tb_password]);

		$this->db->do_insert($this->table, $info);
		// 取得用户的uid
		$uid = $this->db->insert_id();
		if (empty($uid)) {
			return -9;
		} else {
			return $uid;
		}
	}

	/** 发邮件 **/
	function mail(){

	}

	/** 用户登录验证 **/
	function login($username, $password){
		if (empty($username)) $this->message("login", -1);
		if (empty($password)) return -2;

		$user = $this->db->fetchRow("SELECT * FROM {$this->table} WHERE {$this->tb_username}='{$username}'");

		if ($user[$this->tb_password] == md5($password)) {
			// 写入登陆cookie
			$this->setcookie(1, $user);
			return $user;
		} else return -9;
	}

	/** 用户登出 **/
	function logout()
	{
		$this->setcookie(0);
	}

	/** 用户密码修改 **/
	function changePassword ($username, $password)
	{

	}

	/** 设置cookie **/
	function setcookie($write = "1", $user = array() )
	{
		$kvalue = "";

		if ($write == '1') {

			foreach($this->field as $f){
				$kvalue[$f]  = $user[$f];
			}

			if($this->cookie_life ==""){
				$cookie_time = 0;
			}else{
				$cookie_time = time() + $this->cookie_life;
			}
			$this->xsetcookie($this->cookie_key, $this->authcode(serialize($kvalue), 'ENCODE', $this->key_prefix), $cookie_time, "/" ,$this->cookie_domain);
		} else {
			$this->xsetcookie($this->cookie_key, "", time() -1000, "/" ,$this->cookie_domain);
		}
	}

	/** 判断用户是否已登陆 **/
	function isLogin (){
		$auth = isset($_COOKIE[$this->cookie_key]) ? unserialize($this->authcode($_COOKIE[$this->cookie_key], 'DECODE', $this->key_prefix)) : array();
		if (empty($auth)) {
			return false;
		} else {
			$this->uid = $auth['uid'];
			return $auth;
		}
	}

	/** 设置 cookie **/
	function xsetcookie($name, $value = '', $life = 0, $path = '/', $domain='', $israw = false) {
		if($israw) {
			setrawcookie($name, $value, $life, $path, $domain);
		} else {
			setcookie($name, $value, $life, $path, $domain);
		}
	}

	/** 字符串解密加密 **/
	function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {

		$ckey_length = 4;	// 随机密钥长度 取值 0-32;
		// 加入随机密钥，可以令密文无任何规律，即便是原文和密钥完全相同，加密结果也会每次不同，增大破解难度。
		// 取值越大，密文变动规律越大，密文变化 = 16 的 $ckey_length 次方
		// 当此值为 0 时，则不产生随机密钥

		$key  = md5($key ? $key : $this->key_prefix);
		$keya = md5(substr($key, 0, 16));
		$keyb = md5(substr($key, 16, 16));
		$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';

		$cryptkey = $keya.md5($keya.$keyc);
		$key_length = strlen($cryptkey);

		$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
		$string_length = strlen($string);

		$result = '';
		$box = range(0, 255);

		$rndkey = array();
		for($i = 0; $i <= 255; $i++) {
			$rndkey[$i] = ord($cryptkey[$i % $key_length]);
		}

		for($j = $i = 0; $i < 256; $i++) {
			$j = ($j + $box[$i] + $rndkey[$i]) % 256;
			$tmp = $box[$i];
			$box[$i] = $box[$j];
			$box[$j] = $tmp;
		}

		for($a = $j = $i = 0; $i < $string_length; $i++) {
			$a = ($a + 1) % 256;
			$j = ($j + $box[$a]) % 256;
			$tmp = $box[$a];
			$box[$a] = $box[$j];
			$box[$j] = $tmp;
			$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
		}

		if($operation == 'DECODE') {
			if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
				return substr($result, 26);
			} else {
				return '';
			}
		} else {
			return $keyc.str_replace('=', '', base64_encode($result));
		}
	}


	/** 校验用户名格式 **/
	function check_usernameformat($username) {
		$guestexp = '\xA1\xA1|\xAC\xA3|^Guest|^\xD3\xCE\xBF\xCD|\xB9\x43\xAB\xC8';
		$len = strlen($username);

		if($len > 15 || $len < 3 || preg_match("/\s+|^c:\\con\\con|[%,\*\"\s\<\>\&]|$guestexp/is", $username)) {
			return false;
		} else {
			return true;
		}
	}

	/** 用户名是否符合规范 **/
	function check_usernamecensor($username) {
		$censorusername = REGISTER_USERNAME_CENSOR; // 保留的用户名
		$censorexp = '/^('.str_replace(array('\\*', ",", ' '), array('.*', '|', ''), preg_quote(($censorusername = trim($censorusername)), '/')).')$/i';
		if( $censorusername && preg_match($censorexp, $username) ) {
			return false;
		} else {
			return true;
		}
	}

	/** 检查用户名是否已存在 **/
	function check_usernameexists($username) {
		$row = $this->db->fetchRow("SELECT count(1) AS count FROM {$this->table} WHERE {$this->tb_username}='{$username}'");
		if ($row['count'] > 0) {
			return false;
		}else {
			return true;
		}
	}
}
?>
